function  output = bnb_solvelower(lowersolver,relaxed_p,upper,lower,x_min,aggresiveprune,allSolutions)

if all(relaxed_p.lb==relaxed_p.ub)
    x = relaxed_p.lb;
    if checkfeasiblefast(relaxed_p,relaxed_p.lb,relaxed_p.options.bnb.feastol)
        output.problem = 0;
    else
        output.problem = 1;
    end
    output.Primal = x;
    return
end

if ~(relaxed_p.all_integers && all(relaxed_p.c == fix(relaxed_p.c)) && nnz(relaxed_p.Q)==0)
     % Objective contains floating-point numbers, so add some margin
     % if we add an  upper bound cut
     upper = upper + 1e-4;
end

p = relaxed_p;
p.solver.tag = p.solver.lower.tag;

if ~isinf(upper) & nnz(p.Q)==0 & isequal(p.K.m,0) && ~any(p.variabletype)
    if p.all_integers && all(p.c == fix(p.c))
        % All integer objective coefficients and all integer
        % variables, we must find a solution which is at least
        % 1 better than current upper bound
        p.F_struc = [p.F_struc(1:p.K.f,:);upper-1-p.f -p.c';p.F_struc(1+p.K.f:end,:)];
        p.K.l=p.K.l+1;       
    else
%        p.F_struc = [p.F_struc(1:p.K.f,:);upper-p.f -p.c';p.F_struc(1+p.K.f:end,:)];      
%        p.K.l=p.K.l+1;
    end
end

% Exclusion cuts for negated binaries based on some optimal solutions
if ~isinf(upper) && p.all_integers && all(p.ub <= 0) && all(p.lb >= -1)   
    for i = 1:min(size(allSolutions,2),10);
        [b,a] = exclusionCut(allSolutions(:,end-i+1),-1);
        p.F_struc = [p.F_struc(1:p.K.f,:);b a;p.F_struc(1+p.K.f:end,:)];
        p.K.l=p.K.l+1;
    end    
end

removethese = p.lb==p.ub;
if nnz(removethese)>0 & all(p.variabletype == 0) & isempty(p.evalMap)% ~isequal(lowersolver,'callfmincongp') & ~isequal(lowersolver,'callgpposy')
 
    if ~isempty(p.F_struc)
        if ~isequal(p.K.l,0) & p.options.bnb.ineq2eq
            affected = find(any(p.F_struc(:,1+find(removethese)),2));
        end
        p.F_struc(:,1)=p.F_struc(:,1)+p.F_struc(:,1+find(removethese))*p.lb(removethese);
        p.F_struc(:,1+find(removethese))=[];       
    end
        
    idx = find(removethese);
    p.f = p.f + p.c(idx)'*p.lb(idx);
    p.c(idx)=[];
    if nnz(p.Q)>0     
        p.c = p.c + 2*p.Q(find(~removethese),idx)*p.lb(idx);
        p.f = p.f + p.lb(idx)'*p.Q(idx,idx)*p.lb(idx);
        p.Q(:,find(removethese))=[];
        p.Q(find(removethese),:)=[];
    else
        p.Q = spalloc(length(p.c),length(p.c),0);
    end
    p.lb(removethese)=[];
    p.ub(removethese)=[];
    if ~isempty(p.x0)
        p.x0(removethese)=[];
    end
    p.monomtable(:,find(removethese))=[];
    p.monomtable(find(removethese),:)=[];
    
    % This is not necessarily correct!! x*y^2, fix y and we have a linear!
    p.variabletype(removethese) = [];
    % p.variabletype = []; % Reset, to messy to recompute
    if ~isequal(p.K.l,0) & p.options.bnb.ineq2eq
        Beq = p.F_struc(1:p.K.f,1);
        Aeq = -p.F_struc(1:p.K.f,2:end);
        B   = p.F_struc(1+p.K.f:p.K.l+p.K.f,1);
        A   = -p.F_struc(1+p.K.f:p.K.l+p.K.f,2:end);
        affected = affected(affected <= p.K.f + p.K.l);
        affected = affected(affected > p.K.f) - p.K.f;
        aaa = zeros(p.K.l,1);aaa(affected) = 1;
        A1 = A(find(~aaa),:);
        B1 = B(find(~aaa),:);
        [A,B,Aeq2,Beq2,index] = ineq2eq(A(affected,:),B(affected));
        if ~isempty(index)
            actuallyused = find(any([Aeq2,Beq2],2));
            Beq2 = Beq2(actuallyused);if size(Beq2,1)==0;Beq2 = [];end
            Aeq2 = Aeq2(actuallyused,:);if size(Aeq2,1)==0;Aeq2 = [];end
            p.F_struc = [Beq -Aeq;Beq2 -Aeq2;B1 -A1;B -A;p.F_struc(1+p.K.f + p.K.l:end,:)];
            p.K.f = length(Beq) + length(Beq2);
            p.K.l = length(B) + length(B1);
        end
    end
    
    % Find completely empty rows
    zero_row = find(~any(p.F_struc,2));    
    zero_row = zero_row(zero_row <= p.K.f + p.K.l);
    if ~isempty(zero_row)
        p.F_struc(zero_row,:) = [];
        p.K.l =  p.K.l - nnz(zero_row > p.K.f);
        p.K.f =  p.K.f - nnz(zero_row <= p.K.f);
    end
    if p.K.l > 0
         zero_row = find(~any(p.F_struc(1+p.K.f:p.K.f+p.K.l,2:end),2));
         if ~isempty(zero_row)
             lhs = p.F_struc(p.K.f + zero_row,1);
             zero_row_pos = find(lhs >= 0);
             remove_these = zero_row(zero_row_pos);
             p.F_struc(p.K.f + remove_these,:) = [];
             p.K.l = p.K.l - length(remove_these);
             zero_row_neg = find(lhs < -p.options.bnb.feastol);
             if ~isempty(zero_row_neg)
                output.problem = 1;    
                output.Primal = p.lb; 
             end
         end
    end
    
    % Remove zero rows in SOCP cone
	if p.K.q(1) > 0
         top = 1 + p.K.f + p.K.l;
         for j = 1:length(p.K.q)
             m = p.K.q(j);
             M = p.F_struc(top:top+m-1,:);
             remove = any(M,2)==0;
             if any(remove)
                 remove = find(remove);
                 p.F_struc(top + remove-1,:)=[];
                 p.K.q(j) = p.K.q(j)-length(remove);         
             end
              top = top + p.K.q(j);;
         end
    end
                 
%     if relaxed_p.K.q(1) > 0
%         top = 1 + p.K.f + p.K.l;
%         dels = zeros(sum(p.K.q),1);
%         deli = zeros(length(p.K.q),1);
%         for j = 1:length(p.K.q)
%             m = p.K.q(j);
%             M = p.F_struc(top:top+1,:);
%             if nnz(M)==4
%                 if all(M(:,1)==0)
%                     [ii,jj,s] = find(M(1,:));
%                     if all(s==1)
%                         [ii2,jj2,s2] = find(M(2,:));
%                         if isequal(s2,[1 -1]) && isequal(ii,ii2) && isequal(jj,jj2)
%                            if any(isinf(p.ub(jj-1)))
%                                deli(j)=1;
%                                dels(top:top+p.K.q(j)-1)=1;
%                            end
%                         end
%                     end
%                 end
%             end
%             top = top + p.K.q(j);
%         end
%         if any(deli)
%              p.F_struc(find(dels),:)=[];
%              p.K.q(find(deli))=[];
%              if length(p.K.q) == 0
%                  p.K.q = 0;
%              end
%         end
%     end
    
    if p.K.s(1) > 0
        top = 1 + p.K.f + p.K.l + sum(p.K.q);
        newEqualities = [];
        for j = 1:length(p.K.s)
            X = p.F_struc(top:top + p.K.s(j)^2-1,:); 
            X = reshape(any(X,2),p.K.s(j),p.K.s(j));
            e = find(~any(X,2));
            if any(e)
                % Not a single element is used, so simply and reduce SDP
                Z = spalloc(p.K.s(j),p.K.s(j),length(e)*2*p.K.s(j));
                for k = 1:length(e);
                    Z(:,e(k))=1;
                    Z(e(k),:)=1;
                end            
                m = find(Z(:));
                p.F_struc(top + m - 1,:)=[];
                p.K.s(j) = p.K.s(j) - length(e);
            else
                % Look for zero diagonal. This means we can move all
                % nonzero elements to a zero equality                
                e = find(diag(X)==0);
                if length(e)>0
                    Z = spalloc(p.K.s(j),p.K.s(j),length(e)*2*p.K.s(j));
                    for k = 1:length(e);
                        Z(:,e(k))=1;
                        Z(e(k),:)=1;
                    end            
                    m1 = find(Z(:)); % To be removed
                    m2 = find(triu(Z,1)); % To be moved
                    equalityRows = p.F_struc(top + m2 - 1,:);
                    p.F_struc(top + m1 - 1,:) = [];
                    p.K.s(j) = p.K.s(j) - length(e);   
                    equalityRows = equalityRows(find(any(equalityRows,2)),:);
                    newEqualities = [newEqualities;equalityRows];
                end
            end
            top = top + p.K.s(j)^2;
        end
        if ~isempty(newEqualities)
            p.F_struc = [newEqualities;p.F_struc];
            p.K.f = p.K.f + size(newEqualities,1);
        end
    end
                          
    % Derive bounds from this model, and if we fix more variables, apply
    % recursively  
    if isempty(p.F_struc)
        lb = p.lb;
        ub = p.ub;
    else
        [lb,ub] = findulb(p.F_struc,p.K);
    end
    newub = min(ub,p.ub);
    newlb = max(lb,p.lb);
    if any(newub == newlb)
        dummy = p;
        dummy.lb = newlb;
        dummy.ub = newub;
        output = bnb_solvelower(lowersolver,dummy,inf,lower,x_min,aggresiveprune,[]);        
    else
        if any(p.lb>p.ub+0.1)
            output.problem = 1;
            output.Primal = zeros(length(p.lb),1);
        else
            p.solver.version = p.solver.lower.version;
            p.solver.subversion = p.solver.lower.subversion;                                                                          
            output = feval(lowersolver,p);                       
        end
    end
    x=relaxed_p.c*0;
    x(removethese)=relaxed_p.lb(removethese);
    x(~removethese)=output.Primal;
    output.Primal=x;
else
    p.solver = p.solver.lower;
    output = feval(lowersolver,p);    
end



function [A, B, Aeq, Beq, ind_eq] = ineq2eq(A, B)
% Copyright is with the following author(s):
%
% (C) 2006 Johan Loefberg, Automatic Control Laboratory, ETH Zurich,
%          loefberg@control.ee.ethz.ch
% (C) 2005 Michal Kvasnica, Automatic Control Laboratory, ETH Zurich,
%          kvasnica@control.ee.ethz.ch

[ne, nx] = size(A);
Aeq = [];
Beq = [];
ind_eq = [];
if isempty(A)
    return
end
sumM = sum(A, 2) + B;
for ii = 1:ne-1,   
    s = sumM(1);
    
    % get matrix which contains all rows starting from ii+1 
    sumM = sumM(2:end,:);
    
    % possible candidates are those rows whose sum is equal to the sum of the
    % original row
    possible_eq = find(abs(sumM + s) < 1e-12);
    if isempty(possible_eq),
        continue
    end
    possible_eq = possible_eq + ii;
    b1 = B(ii);    
    a1 = A(ii,  :) ;
    
    % now compare if the two inequalities (the second one with opposite
    % sign) are really equal (hence they form an equality constraint)
    for jj = possible_eq',
        % first compare the B part, this is very cheap
        if abs(b1 + B(jj)) < 1e-12,
            % now compare the A parts as well
            if norm(a1 + A(jj,  :) , Inf) < 1e-12,
                % jj-th inequality together with ii-th inequality forms an equality
                % constraint
                ind_eq = [ind_eq; ii jj];
                break
            end
        end
    end
end

if isempty(ind_eq),
    % no equality constraints
    return
else
    % indices of remaining constraints which are inequalities
    ind_ineq = setdiff(1:ne, ind_eq(:));
    Aeq = A(ind_eq(:,1),  :) ;
    Beq = B(ind_eq(:,1));
    A = A(ind_ineq,  :) ;
    B = B(ind_ineq);
end